package com.km.metric;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Metric 工厂类
 *
 * @author Jack(yebin.xm @ gmail.com)
 */
public class MetricFactory implements Runnable {
    private static final Logger log = LoggerFactory.getLogger(MetricFactory.class);
    private static MetricFactory instance;
    private String apiUrl;
    private String serviceNmae;
    private Integer port;
    private boolean init = false;
    private ScheduledExecutorService exes = Executors.newSingleThreadScheduledExecutor();

    private MetricFactory() {
    }

    public static MetricFactory getInstance() {
        if (instance == null) {
            synchronized (MetricFactory.class) {
                if (instance == null) {
                    instance = new MetricFactory();
                }
            }
        }
        return instance;
    }

    public void setServiceInfo(String serviceName, Integer port, boolean init) {
        this.serviceNmae = serviceName;
        this.port = port;
        this.init = init;
        init();
    }

    public void setServiceInfo(String serviceName, Integer port) {
        this.serviceNmae = serviceName;
        this.port = port;
        init();
    }

    public void setServiceInfo(String serviceName) {
        this.serviceNmae = serviceName;
        init();
    }

    private void init() {
        if (this.init) {
            exes.scheduleAtFixedRate(this, 1, 1, TimeUnit.MINUTES);
            this.init = false;

            // 获取上报地址
            String host = System.getProperty("host");
            String port = System.getProperty("port", "55555");
            if (null == host || "".equals(host)) {
                InetAddress inetAddress = getLocalHostLANAddress();
                if (null == inetAddress) {
                    System.out.println("未获取到本地的主机地址");
                    return;
                }
                host = inetAddress.getHostAddress();
            }
            apiUrl = "http://" + host + ":" + port + "/javainfo";
            log.info("监控上报地址: {}", apiUrl);
        }else {
            log.info("当前不执行监控上报...");
        }
    }

    public String getServiceNmae() {
        return serviceNmae;
    }


    public Integer getPort() {
        return port;
    }

    public void setPort(Integer port) {
        this.port = port;
    }

    private InetAddress getLocalHostLANAddress() {
        try {
            InetAddress candidateAddress = null;
            // 遍历所有的网络接口
            for (Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces(); ifaces
                    .hasMoreElements(); ) {
                NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
                // 在所有的接口下再遍历IP
                for (Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) {
                    InetAddress inetAddr = inetAddrs.nextElement();
                    // 排除loopback类型地址
                    if (!inetAddr.isLoopbackAddress()) {
                        // 如果是site-local地址，就是它了
                        if (inetAddr.isSiteLocalAddress()) {
                            return inetAddr;
                        } else if (candidateAddress == null) {
                            // site-local类型的地址未被发现，先记录候选地址
                            candidateAddress = inetAddr;
                        }
                    }
                }
            }
            if (candidateAddress != null) {
                return candidateAddress;
            }
            // 如果没有发现 non-loopback地址.只能用最次选的方案 返回本地地址
            InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
            return jdkSuppliedAddress;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void run() {
        PrivateHttpClient.doPostAsJson(apiUrl, MetricBuilder.currentMetric());
        log.debug("send ok, param: {}", MetricBuilder.currentMetric());
//        System.out.println("send ok");
    }
}
